﻿///////////////////////////////////////////////////////////////////////////////
//
// wxFormBuilder - A Visual Dialog Editor for wxWidgets.
// Copyright (C) 2005 José Antonio Hurtado
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Written by
//   José Antonio Hurtado - joseantonio.hurtado@gmail.com
//   Juan Antonio Ortega  - jortegalalmolda@gmail.com
//
///////////////////////////////////////////////////////////////////////////////

#include "database.h"
#include "objectbase.h"
#include <assert.h>
#include "../utils/typeconv.h"
#include "../utils/wxfbexception.h"
#include "../utils/stringutils.h"


//#include "../rad/bitmaps.h"
// #include "../utils/debug.h"
// #include <ticpp.h>

//#define DEBUG_PRINT(x) cout << x

#define OBJINFO_TAG "objectinfo"
#define CODEGEN_TAG "codegen"
#define TEMPLATE_TAG "template"
#define NAME_TAG "name"
#define DESCRIPTION_TAG "help"
#define CUSTOM_EDITOR_TAG "editor"
#define PROPERTY_TAG "property"
#define CHILD_TAG "child"
#define EVENT_TAG "event"
#define EVENT_CLASS_TAG "class"
#define CATEGORY_TAG "category"
#define OBJECT_TAG "object"
#define CLASS_TAG "class"
#define PACKAGE_TAG "package"
#define PKGDESC_TAG "desc"
#define PRGLANG_TAG "language"
#define ICON_TAG "icon"
#define SMALL_ICON_TAG "smallIcon"
#define EXPANDED_TAG "expanded"
#define WXVERSION_TAG "wxversion"
#define VALUE_TAG   "value"
#define LOCKED_EDITOR_TAG  "locked"


ObjectPackage::ObjectPackage(QString name, QString desc, QBitmap icon)
{
	m_name = name;
	m_desc = desc;
	m_icon = icon;
}

PObjectInfo ObjectPackage::GetObjectInfo(unsigned int idx)
{
	assert (idx < m_objs.size());
	return m_objs[idx];
}

void ObjectPackage::AppendPackage( PObjectPackage package )
{
	m_objs.insert( m_objs.end(), package->m_objs.begin(), package->m_objs.end() );
}

///////////////////////////////////////////////////////////////////////////////

ObjectDatabase::ObjectDatabase()
{
	InitPropertyTypes();
}

ObjectDatabase::~ObjectDatabase()
{

}

PObjectInfo ObjectDatabase::GetObjectInfo(QString class_name)
{
	PObjectInfo info;
	ObjectInfoMap::iterator it = m_objs.find( class_name );

	if ( it != m_objs.end() )
	{
		info = it->second;
	}

	return info;
}

PObjectPackage ObjectDatabase::GetPackage(unsigned int idx)
{
	assert (idx < m_pkgs.size());

	return m_pkgs[idx];
}


/**
* @todo La herencia de propiedades ha de ser de forma recursiva.
*/

PObjectBase ObjectDatabase::NewObject(PObjectInfo obj_info)
{
	PObjectBase object;
    //LogDebug((" ObjectDatabase::NewObject"));
	// Llagados aquí el objeto se crea seguro...
	object = PObjectBase(new ObjectBase(obj_info->GetClassName()));
	object->SetObjectTypeName(obj_info->GetObjectTypeName()); // *FIXME*

	object->SetObjectInfo(obj_info);

	PPropertyInfo prop_info;
	PEventInfo    event_info;
	PObjectInfo   class_info = obj_info;

	unsigned int base = 0;

	while (class_info)
	{
		unsigned int i;
		for (i = 0; i < class_info->GetPropertyCount(); i++)
		{
			prop_info = class_info->GetPropertyInfo(i);

			PProperty property(new Property(prop_info, object));

			// Set the default value, either from the property info, or an override from this class
			QString defaultValue = prop_info->GetDefaultValue();
			if ( base > 0 )
			{
				QString defaultValueTemp = obj_info->GetBaseClassDefaultPropertyValue( base - 1, prop_info->GetName() );
                if ( !defaultValueTemp.isEmpty() )
				{
					defaultValue = defaultValueTemp;
				}
			}
            //LogDebug((" ObjectDatabase::NewObject defaultValue=%s"), defaultValue.c_str());
			property->SetValue( defaultValue );

			// Las propiedades están implementadas con una estructura "map",
			// ello implica que no habrá propiedades duplicadas.
			// En otro caso habrá que asegurarse de que dicha propiedad
			// no existe.
			// Otra cosa importante, es que el orden en que se insertan
			// las propiedades, de abajo-arriba, esto permite que se pueda redefir
			// alguna propiedad.
			object->AddProperty (property);
		}

		for (i=0; i < class_info->GetEventCount(); i++)
		{
		  event_info = class_info->GetEventInfo(i);
		  PEvent event(new Event(event_info,object));
		  // notice that for event there isn't a default value on its creation
		  // because there is not handler at the moment
		  object->AddEvent(event);
		}

		class_info = ( base < obj_info->GetBaseClassCount() ?
			obj_info->GetBaseClass(base++) : PObjectInfo());
	}

	// si el objeto tiene la propiedad name (reservada para el nombre del
	// objeto) le añadimos el contador para no repetir nombres.

	obj_info->IncrementInstanceCount();

    // 注释掉对name本身的修改
	// unsigned int ins = obj_info->GetInstanceCount();
    // PProperty pname = object->GetProperty( (NAME_TAG) );
	// if (pname)
	// 	pname->SetValue(pname->GetValue() + StringUtils::IntToStr(ins));

	return object;
}


int ObjectDatabase::CountChildrenWithSameType(PObjectBase parent,PObjectType type)
{
	unsigned int count = 0;
	unsigned int numChildren = parent->GetChildCount();
	for (unsigned int i=0; i < numChildren ; i++)
	{
		if (type == parent->GetChild(i)->GetObjectInfo()->GetObjectType())
			count++;
	}

	return count;
}

int ObjectDatabase::CountChildrenWithSameType(PObjectBase parent, const std::set<PObjectType>& types)
{
	unsigned int count = 0;
	unsigned int numChildren = parent->GetChildCount();
	for (unsigned int i = 0; i < numChildren; ++i)
	{
		if (types.find(parent->GetChild(i)->GetObjectInfo()->GetObjectType()) != types.end())
			++count;
	}

	return count;
}

/**
* Crea una instancia de classname por debajo de parent.
* La función realiza la comprobación de tipos para crear el objeto:
* - Comprueba si el tipo es un tipo-hijo válido de "parent", en cuyo caso
*   se comprobará también que el número de hijos del mismo tipo no sobrepase
el máximo definido. El objeto no se crea si supera el máximo permitido.
* - Si el tipo-hijo no se encuentra entre los definidos para el tipo de
*   "parent" se intentará crearlo como hijo de alguno de los tipos hijos con el
*   flag item a "1". Para ello va recorriendo todos los tipos con flag item,
*   si no puede crear el objeto, bien por que el tipo no es válido o porque
*   sobrepasa el máximo permitido si intenta con el siguiente hasta que no queden
*   más.
*
* Nota: quizá sea conveniente que el método cree el objeto sin enlazarlo
*       en el árbol, para facilitar el undo-redo.
*/
PObjectBase ObjectDatabase::CreateObject( std::string classname, PObjectBase parent)
{
    //LogDebug("[ObjectDatabase::CreateObject] classname:" + QString(classname));
	PObjectBase object;
	PObjectInfo objInfo = GetObjectInfo( _WXSTR(classname) );

	if (!objInfo)
	{
//        THROW_WXFBEX( 	("Unknown Object Type: ") << _WXSTR(classname) << ("\n")
//                        ("The most likely causes are that this copy of Bitmotion Designer is out of date, or that there is a plugin missing.\n")
//                        ("Please check at http://www.bitmotion.cn") << ("\n") )
	}

	PObjectType objType = objInfo->GetObjectType();
    //LogDebug("[ObjectDatabase::CreateObject] objInfo objType:" + objType->GetName());
	if (parent)
	{
		// Comprobamos si el tipo es válido
		PObjectType parentType = parent->GetObjectInfo()->GetObjectType();
        //LogDebug("[ObjectDatabase::CreateObject] parentType objType:" + parentType->GetName());
		//AUI
		bool aui = false;
        if( parentType->GetName() == ("form") )
		{
            aui = parent->GetPropertyAsInteger(("aui_managed")) != 0;
		}

		int max = parentType->FindChildType(objType, aui);
        //LogDebug("[ObjectDatabase::CreateObject] parentType ChildType max:%d,aui:%d", max, aui);
		// FIXME! Esto es un parche para evitar crear los tipos menubar,statusbar y
		// toolbar en un form que no sea wxFrame.
		// Hay que modificar el conjunto de tipos para permitir tener varios tipos
		// de forms (como childType de project), pero hay mucho código no válido
		// para forms que no sean de tipo "form". Dicho de otra manera, hay
		// código que dependen del nombre del tipo, cosa que hay que evitar.
        if (parentType->GetName() == ("form") && parent->GetClassName() != ("Frame") &&
            (objType->GetName() == ("statusbar") ||
            objType->GetName() == ("menubar") ||
            objType->GetName() == ("ribbonbar") ||
            objType->GetName() == ("toolbar") ))
			return PObjectBase(); // tipo no válido

        // No menu dropdown for oolBar until wx 2.9 :(
        if ( parentType->GetName() == ("tool") )
		{
			PObjectBase gParent = parent->GetParent();
			if (
                ( gParent->GetClassName() == ("oolBar") ) &&
                ( objType->GetName() == ("menu") )
			)
				return PObjectBase(); // not a valid type
		}

		if (max != 0) // tipo válido
		{
			bool create = true;

			// we check the number of instances
			int count;
            if (objType == GetObjectType(("sizer")) || objType == GetObjectType(("gbsizer")))
			{
                count = CountChildrenWithSameType(parent, { GetObjectType(("sizer")), GetObjectType(("gbsizer")) });
				//LogDebug("[ObjectDatabase::CreateObject] CountChildrenWithSameType if count:%d", count);
			}
			else 
			{
				count = CountChildrenWithSameType(parent, objType);
				//LogDebug("[ObjectDatabase::CreateObject] CountChildrenWithSameType else count:%d", count);
			}
			if (max > 0 && count >= max)
				create = false;

			if (create)
				object = NewObject(objInfo);
		}
		else // max == 0
		{
			// el tipo no es válido, vamos a comprobar si podemos insertarlo
			// como hijo de un "item"
			bool created = false;
			for (unsigned int i=0; !created && i < parentType->GetChildTypeCount(); i++)
			{
				PObjectType childType = parentType->GetChildType(i);
				int childMax = childType->FindChildType(objType, aui);

				if (childType->IsItem() && childMax != 0)
				{
					childMax = parentType->FindChildType(childType, aui);

					// si el tipo es un item y además el tipo del objeto a crear
					// puede ser hijo del tipo del item vamos a intentar crear la
					// instancia del item para crear el objeto como hijo de este
					if (childMax < 0 || CountChildrenWithSameType(parent, childType) < childMax)
					{
						// No hay problemas para crear el item debajo de parent
						PObjectBase item = NewObject(GetObjectInfo(childType->GetName()));

						//PObjectBase obj = CreateObject(classname,item);
						PObjectBase obj = NewObject(objInfo);

						// la siguiente condición debe cumplirse siempre
						// ya que un item debe siempre contener a otro objeto
						if (obj)
						{
							// enlazamos item y obj
							item->AddChild(obj);
							obj->SetParent(item);

							// sizeritem es un tipo de objeto reservado, para que el uso sea
							// más práctico se asignan unos valores por defecto en función
							// del tipo de objeto creado
                            if ( item->GetObjectInfo()->IsSubclassOf( ("sizeritembase") ) )
								SetDefaultLayoutProperties(item);

							object = item;
							created = true;
						}
						else
                            ;////wxLogError(("Review your definitions file (objtypes.xml)"));
					}
				}
			}
		}
		///////////////////////////////////////////////////////////////////////
		// Nota: provisionalmente vamos a enlazar el objeto al padre pero
		//       esto debería hacerse fuera para poder implementar el Undo-Redo
		///////////////////////////////////////////////////////////////////////
		//if (object)
		//{
		//  parent->AddChild(object);
		//  object->SetParent(parent);
		//}
	}
	else // parent == NULL;
	{
		object = NewObject(objInfo);
	}

	return object;
}

PObjectBase ObjectDatabase::CopyObject(PObjectBase obj)
{
	assert(obj);

	PObjectInfo objInfo = obj->GetObjectInfo();

	PObjectBase copyObj = NewObject(objInfo); // creamos la copia
	assert(copyObj);

	// copiamos las propiedades
	unsigned int i;
	unsigned int count = obj->GetPropertyCount();
	for (i = 0; i < count; i++)
	{
		PProperty objProp = obj->GetProperty(i);
		assert(objProp);

		PProperty copyProp = copyObj->GetProperty(objProp->GetName());
		assert(copyProp);

		QString propValue = objProp->GetValue();
		copyProp->SetValue(propValue);
	}

	// ...and the event handlers
	count = obj->GetEventCount();
	for (i = 0; i < count; i++)
	{
	  PEvent event = obj->GetEvent(i);
	  PEvent copyEvent = copyObj->GetEvent(event->GetName());
	  copyEvent->SetValue(event->GetValue());
	  copyEvent->SetFuncBody(event->GetFuncBody());
	}

	// creamos recursivamente los hijos
	count = obj->GetChildCount();
	for (i = 0; i<count; i++)
	{
		PObjectBase childCopy = CopyObject(obj->GetChild(i));
		copyObj->AddChild(childCopy);
		childCopy->SetParent(copyObj);
	}

	return copyObj;
}

void ObjectDatabase::SetDefaultLayoutProperties(PObjectBase sizeritem)
{
    if ( !sizeritem->GetObjectInfo()->IsSubclassOf( ("sizeritembase") ) )
	{
        //LogDebug( ("SetDefaultLayoutProperties expects a subclass of sizeritembase") );
		return;
	}

	PObjectBase child = sizeritem->GetChild(0);
	PObjectInfo childInfo = child->GetObjectInfo();
	QString obj_type = child->GetObjectTypeName();

    PProperty proportion = sizeritem->GetProperty( ("proportion") );

    if ( childInfo->IsSubclassOf( ("sizer") ) || childInfo->IsSubclassOf( ("gbsizer") ) || obj_type == ("splitter") || childInfo->GetClassName() == ("spacer") )
	{
		if ( proportion )
		{
            proportion->SetValue( ("1") );
		}
        sizeritem->GetProperty( ("flag") )->SetValue( ("wxEXPAND") );
	}
    else if ( childInfo->GetClassName() == ("wxStaticLine") )
	{
        sizeritem->GetProperty( ("flag") )->SetValue( ("wxEXPAND | wxALL") );
	}
    else if ( childInfo->GetClassName() == ("oolBar") )
	{
        sizeritem->GetProperty( ("flag") )->SetValue( ("wxEXPAND") );
	}
    else if ( obj_type == ("widget") || obj_type == ("statusbar") )
	{
		if ( proportion )
		{
            proportion->SetValue( ("0") );
		}
        sizeritem->GetProperty( ("flag") )->SetValue( ("wxALL") );
	}
    else if (	obj_type == ("notebook")			||
                obj_type == ("flatnotebook")		||
                obj_type == ("listbook")			||
                obj_type == ("simplebook")       ||
                obj_type == ("choicebook")		||
                obj_type == ("auinotebook")		||
                obj_type == ("treelistctrl")		||
                obj_type == ("expanded_widget")	||
                obj_type == ("container")
				)
	{
		if ( proportion )
		{
            proportion->SetValue( ("1") );
		}
        sizeritem->GetProperty( ("flag") )->SetValue( ("wxEXPAND | wxALL") );
	}
}

void ObjectDatabase::ResetObjectCounters()
{
	ObjectInfoMap::iterator it;
	for (it = m_objs.begin() ; it != m_objs.end() ; it++)
	{
		it->second->ResetInstanceCount();
	}
}

///////////////////////////////////////////////////////////////////////

PObjectBase ObjectDatabase::CreateObject( ticpp::Element* xml_obj, PObjectBase parent )
{
	try
	{
		std::string class_name;
		xml_obj->GetAttribute( CLASS_TAG, &class_name, false );

		PObjectBase newobject = CreateObject( class_name, parent );

		// It is possible the CreateObject returns an "item" containing the object, e.g. SizerItem or SplitterItem
		// If that is the case, reassign "object" to the actual object
		PObjectBase object = newobject;
		if ( object && object->GetChildCount() > 0 )
		{
			object = object->GetChild( 0 );
		}

		if ( object )
		{
			// Get the state of expansion in the object tree
			bool expanded;
			xml_obj->GetAttributeOrDefault( EXPANDED_TAG, &expanded, true );
			object->SetExpanded( expanded );
            
			bool isLocked; 
            xml_obj->GetAttributeOrDefault( LOCKED_EDITOR_TAG, &isLocked, false );
			object->SetLockEditor( isLocked );
			// Load the properties
			ticpp::Element* xml_prop = xml_obj->FirstChildElement( PROPERTY_TAG, false );
			while ( xml_prop )
			{
				std::string prop_name;
				xml_prop->GetAttribute( NAME_TAG, &prop_name, false );
				PProperty prop = object->GetProperty( _WXSTR(prop_name) );

				if ( prop ) // does the property exist
				{
					// load the value
					prop->SetValue( _WXSTR( xml_prop->GetText( false ) ) );
				}
				else
				{
					std::string value = xml_prop->GetText( false );
					// if ( !value.empty() )
					// {
                    // 	//wxLogError( ("The property named \"%s\" of class \"%s\" is not supported by this version of Bitmotion designer.\n")
                    // 				("If your project file was just converted from an older version, then the conversion was not complete.\n")
                    // 				("Otherwise, this project is from a newer version of Bitmotion designer.\n\n")
                    // 				("The property's value is: %s\n")
                    // 				("If you save this project, YOU WILL LOSE DATA"), _WXSTR(prop_name).c_str(), _WXSTR(class_name).c_str(), _WXSTR(value).c_str() );
					// }
				}

				xml_prop = xml_prop->NextSiblingElement( PROPERTY_TAG, false );
			}

			// load the event handlers
			ticpp::Element* xml_event = xml_obj->FirstChildElement( EVENT_TAG, false );
			while ( xml_event )
			{
				std::string event_name;
				xml_event->GetAttribute( NAME_TAG, &event_name, false );
				PEvent event = object->GetEvent( _WXSTR(event_name) );
				if ( event )
				{
					//event->SetValue( _WXSTR( xml_event->GetText( false ) ) );
					std::string event_value;
					xml_event->GetAttribute( VALUE_TAG, &event_value, false );
					event->SetValue( _WXSTR(event_value) );
					event->SetFuncBody( _WXSTR( xml_event->GetText( false ) ) );
				}

				xml_event = xml_event->NextSiblingElement( EVENT_TAG, false );
			}


			if ( parent )
			{
				// set up parent/child relationship
				parent->AddChild( newobject );
				newobject->SetParent( parent );
			}

			// create the children
			ticpp::Element* child = xml_obj->FirstChildElement( OBJECT_TAG, false );
			while ( child )
			{
				CreateObject( child, object );
				child = child->NextSiblingElement( OBJECT_TAG, false );
			}
		}

		return newobject;
	}
	catch( ticpp::Exception& )
	{
		return PObjectBase();
	}
}

//////////////////////////////

bool IncludeInPalette(QString /*type*/) {
	return true;
}



void ObjectDatabase::SetupPackage(const QString& file,
#ifdef __WXMSW__
                                  const QString& path,
#else
                                  const QString& /*path*/,
#endif
                                  PwxFBManager manager) {
//	#ifdef __WXMSW__
//		QString libPath = path;
//	#else
//		wxStandardPathsBase& stdpaths = wxStandardPaths::Get();
//		QString libPath = stdpaths.GetPluginsDir();
//        libPath.Replace( heApp->GetAppName().c_str(), ("BMDesginer") );
//	#endif

//    // Renamed libraries for convenience in debug using a "-xx" wx version as suffix.
//    // This will also prevent loading debug libraries in release and vice versa,
//    // that used to cause crashes when trying to debug.
//    QString wxver = ("");

//#ifdef DEBUG
//	#ifdef APPEND_WXVERSION
//        wxver = wxver + QString::Format( ("-%i%i"), wxMAJOR_VERSION, wxMINOR_VERSION );
//	#endif
//#endif

//	try
//	{
//		ticpp::Document doc;
//		XMLUtils::LoadXMLFile( doc, true, file );

//		ticpp::Element* root = doc.FirstChildElement( PACKAGE_TAG );

//		// get the library to import
//		std::string lib;
//		root->GetAttributeOrDefault( "lib", &lib, "" );
//		if ( !lib.empty() )
//		{
//			// Allows plugin dependency dlls to be next to plugin dll in windows
//			QString workingDir = ::wxGetCwd();
//			wxFileName::SetCwd( libPath );
//			try
//			{
//				QString fullLibPath = libPath + wxFILE_SEP_PATH + _WXSTR(lib) + wxver;
//				if ( m_importedLibraries.insert( fullLibPath ).second )
//				{
//					ImportComponentLibrary( fullLibPath, manager );
//				}
//			}
//			catch ( ... )
//			{
//				// Put Cwd back
//				wxFileName::SetCwd( workingDir );
//				throw;
//			}

//			// Put Cwd back
//			wxFileName::SetCwd( workingDir );
//		}

//		ticpp::Element* elem_obj = root->FirstChildElement( OBJINFO_TAG, false );
//		while ( elem_obj )
//		{
//			std::string wxver_obj;
//			elem_obj->GetAttributeOrDefault(WXVERSION_TAG, &wxver_obj, "");
//			if (!wxver_obj.empty())
//			{
//				long wxversion = 0;
//				// skip widgets supported by higher wxWidgets version than used for the build
//				if((!_WXSTR(wxver_obj).ToLong(&wxversion)) || (wxversion > wxVERSION_NUMBER))
//				{
//					elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
//					continue;
//				}
//			}

//			std::string class_name;
//			elem_obj->GetAttribute( CLASS_TAG, &class_name );

//			PObjectInfo class_info = GetObjectInfo( _WXSTR(class_name) );

//			ticpp::Element* elem_base = elem_obj->FirstChildElement( "inherits", false );
//			while ( elem_base )
//			{
//				std::string base_name;
//				elem_base->GetAttribute( CLASS_TAG, &base_name );

//				// Add a reference to its base class
//				PObjectInfo base_info  = GetObjectInfo( _WXSTR(base_name) );
//				if ( class_info && base_info )
//				{
//					size_t baseIndex = class_info->AddBaseClass( base_info );

//					std::string prop_name, value;
//					ticpp::Element* inheritedProperty = elem_base->FirstChildElement( "property", false );
//					while( inheritedProperty )
//					{
//						inheritedProperty->GetAttribute( NAME_TAG, &prop_name );
//						value = inheritedProperty->GetText();
//						class_info->AddBaseClassDefaultPropertyValue( baseIndex, _WXSTR(prop_name), _WXSTR(value) );
//						inheritedProperty = inheritedProperty->NextSiblingElement( "property", false );
//					}
//				}
//				elem_base = elem_base->NextSiblingElement( "inherits", false );
//			}

//			// Add the "C++" base class, predefined for the components and widgets
//			QString typeName = class_info->GetObjectTypeName();
//			if ( HasCppProperties( typeName ) )
//			{
//                PObjectInfo cpp_interface = GetObjectInfo( ("C++") );
//				if ( cpp_interface )
//				{
//					size_t baseIndex = class_info->AddBaseClass( cpp_interface );
//                    if (    typeName == ("sizer")    ||
//                            typeName == ("gbsizer")  ||
//                            typeName == ("menuitem")  )
//					{
//                        class_info->AddBaseClassDefaultPropertyValue( baseIndex, ("permission"), ("none") );
//					}
//				}
//			}

//			elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
//		}
//	}
//	catch ( ticpp::Exception& ex )
//	{
//		THROW_WXFBEX( _WXSTR(ex.m_details) );
//	}
}

bool ObjectDatabase::HasCppProperties(QString type)
{
    return (type == ("notebook")			||
            type == ("flatnotebook")		||
            type == ("listbook")			||
            type == ("simplebook")		||
            type == ("choicebook")		||
            type == ("auinotebook")		||
            type == ("widget")			||
            type == ("expanded_widget")	||
            type == ("propgrid")	||
            type == ("propgridman")	||
            type == ("statusbar")		   ||
            type == ("component")		   ||
            type == ("container")		   ||
            type == ("menubar")			   ||
            type == ("menu")				   ||
            type == ("menuitem")			   ||
            type == ("submenu")			   ||
            type == ("toolbar")			   ||
            type == ("ribbonbar")			||
            type == ("ribbonpage")			||
            type == ("ribbonpanel")			||
            type == ("ribbonbuttonbar")		||
            type == ("ribbonbutton")			||
            type == ("ribbondropdownbutton" )	||
            type == ("ribbonhybridbutton" ) 	||
            type == ("ribbontogglebutton" ) 	||
            type == ("ribbontoolbar")	   		||
            type == ("ribbontool")		   	||
            type == ("ribbondropdowntool" )  	||
            type == ("ribbonhybridtool" )  		||
            type == ("ribbontoggletool" )  		||
            type == ("ribbongallery")	   		||
            type == ("ribbongalleryitem")   		||
            type == ("dataviewctrl")		   	||
            type == ("dataviewtreectrl")	  	||
            type == ("dataviewlistctrl")	   	||
            type == ("dataviewlistcolumn")	   	||
            type == ("dataviewcolumn")	   	||
            type == ("tool")				||
            type == ("splitter")			||
            type == ("treelistctrl")		||
            type == ("sizer")			||
            type == ("nonvisual")		||
            type == ("gbsizer")          ||
            type == ("propgriditem")          ||
            type == ("propgridpage")          ||
            type == ("gbsizer")          ||
            type == ("wizardpagesimple")
			);
}

void ObjectDatabase::LoadCodeGen( const QString& file )
{
	try
	{
        //LogDebug( "ObjectDatabase::LoadCodeGen file: \"" + file + "\"" );
		ticpp::Document doc;
		XMLUtils::LoadXMLFile( doc, true, file );

		// read the codegen element
		ticpp::Element* elem_codegen = doc.FirstChildElement("codegen");
		std::string language;
		elem_codegen->GetAttribute( "language", &language );
		QString lang = _WXSTR(language);

		// read the templates
		ticpp::Element* elem_templates = elem_codegen->FirstChildElement( "templates", false );
		while ( elem_templates  )
		{

			std::string prop_name;
			elem_templates->GetAttribute( "property", &prop_name, false );
			bool hasProp = !prop_name.empty();

			std::string class_name;
			elem_templates->GetAttribute( "class", &class_name, !hasProp );

			PCodeInfo code_info( new CodeInfo() );

			ticpp::Element* elem_template = elem_templates->FirstChildElement( "template", false );
			while ( elem_template )
			{
				std::string template_name;
				elem_template->GetAttribute( "name", &template_name );

				std::string template_code = elem_template->GetText( false );

				code_info->AddTemplate( _WXSTR(template_name), _WXSTR(template_code) );

				elem_template = elem_template->NextSiblingElement( "template", false );
			}

			if ( hasProp )
			{
				// store code info for properties
				if ( !m_propertyTypeTemplates[ ParsePropertyType( _WXSTR(prop_name) ) ].insert( LangTemplateMap::value_type( lang, code_info ) ).second )
				{
                    ////wxLogError( ("Found second template definition for property \"%s\" for language \"%s\""), _WXSTR(prop_name).c_str(), lang.c_str() );
				}
			}
			else
			{
				// store code info for objects
				PObjectInfo obj_info = GetObjectInfo( _WXSTR(class_name) );
				if ( obj_info )
				{
                    ////wxLogDebug(("ObjectDatabase::LoadCodeGen lang=%s"), lang);
					obj_info->AddCodeInfo( lang, code_info );
				}
			}

			elem_templates = elem_templates->NextSiblingElement( "templates", false );
		}
	}
	catch( ticpp::Exception& ex )
	{
        ////wxLogError( _WXSTR(ex.m_details) );
	}
	catch( wxFBException& ex )
	{
        ////wxLogError( ex.what() );
	}
}

PObjectPackage ObjectDatabase::LoadPackage( const QString& file, const QString& iconPath )
{
	PObjectPackage package;

//	try
//	{
//		ticpp::Document doc;
//		XMLUtils::LoadXMLFile( doc, true, file );

//		ticpp::Element* root = doc.FirstChildElement( PACKAGE_TAG );

//		// Name Attribute
//		std::string pkg_name;
//		root->GetAttribute( NAME_TAG, &pkg_name );

//		// Description Attribute
//		std::string pkg_desc;
//		root->GetAttributeOrDefault( PKGDESC_TAG, &pkg_desc, "" );

//		// Icon Path Attribute
//		std::string pkgIconName;
//		root->GetAttributeOrDefault( ICON_TAG, &pkgIconName, "" );
//		QString pkgIconPath = iconPath + wxFILE_SEP_PATH +  _WXSTR(pkgIconName);

//		QBitmap pkg_icon;
//		if ( !pkgIconName.empty() && wxFileName::FileExists( pkgIconPath ) )
//		{
//			wxImage image( pkgIconPath, QBitmap_TYPE_ANY );
//			pkg_icon = QBitmap( image.Scale( 16, 16 ) );
//		}
//		else
//		{
//            pkg_icon = AppBitmaps::GetBitmap( ("unknown"), 16 );
//		}

//		package = PObjectPackage ( new ObjectPackage( _WXSTR(pkg_name), _WXSTR(pkg_desc), pkg_icon ) );


//		ticpp::Element* elem_obj = root->FirstChildElement( OBJINFO_TAG, false );

//		while (elem_obj)
//		{
//			std::string class_name;
//			std::string name;
//			elem_obj->GetAttribute( CLASS_TAG, &class_name );
//			elem_obj->GetAttribute( NAME_TAG, &name );

//			std::string type;
//			elem_obj->GetAttribute( "type", &type );

//			std::string icon;
//			elem_obj->GetAttributeOrDefault( "icon", &icon, "" );
//			QString iconFullPath = iconPath + wxFILE_SEP_PATH + _WXSTR(icon);

//			std::string smallIcon;
//			elem_obj->GetAttributeOrDefault( "smallIcon", &smallIcon, "" );
//			QString smallIconFullPath = iconPath + wxFILE_SEP_PATH + _WXSTR(smallIcon);

//			std::string wxver;
//			elem_obj->GetAttributeOrDefault( WXVERSION_TAG, &wxver, "" );
//			if( wxver != "" )
//			{
//				long wxversion = 0;
//				// skip widgets supported by higher wxWidgets version than used for the build
//				if( (! _WXSTR(wxver).ToLong( &wxversion ) ) || (wxversion > wxVERSION_NUMBER) )
//				{
//					elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
//					continue;
//				}
//			}

//			bool startGroup;
//			elem_obj->GetAttributeOrDefault( "startgroup", &startGroup, false );

//			PObjectInfo obj_info( new ObjectInfo( _WXSTR(class_name),  _WXSTR(name),GetObjectType( _WXSTR(type) ), package, startGroup ) );

//			if ( !icon.empty() && wxFileName::FileExists( iconFullPath ) )
//			{
//				wxImage img( iconFullPath, QBitmap_TYPE_ANY );
//				obj_info->SetIconFile( QBitmap( img.Scale( ICON_SIZE, ICON_SIZE ) ) );
//			}
//			else
//			{
//                obj_info->SetIconFile( AppBitmaps::GetBitmap( ("unknown"), ICON_SIZE ) );
//			}

//			if ( !smallIcon.empty() && wxFileName::FileExists( smallIconFullPath ) )
//			{
//				wxImage img( smallIconFullPath, QBitmap_TYPE_ANY );
//				obj_info->SetSmallIconFile( QBitmap( img.Scale( SMALL_ICON_SIZE, SMALL_ICON_SIZE ) ) );
//			}
//			else
//			{
//				wxImage img = obj_info->GetIconFile().ConvertToImage();
//				obj_info->SetSmallIconFile( QBitmap( img.Scale( SMALL_ICON_SIZE, SMALL_ICON_SIZE ) ) );
//			}

//			// Parse the Properties
//			std::set< PropertyType > types;
//			ParseProperties( elem_obj, obj_info, obj_info->GetCategory(), &types );
//			ParseEvents    ( elem_obj, obj_info, obj_info->GetCategory() );

//			// Add the ObjectInfo to the map
//			m_objs.insert(ObjectInfoMap::value_type( _WXSTR(class_name), obj_info ) );

//			// Add the object to the palette
//			if ( ShowInPalette( obj_info->GetObjectTypeName() ) )
//			{
//				package->Add( obj_info );
//			}

//			elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
//		}
//	}
//	catch ( ticpp::Exception& ex )
//	{
//		THROW_WXFBEX( _WXSTR(ex.m_details) );
//	}

	return package;
}

void ObjectDatabase::ParseProperties( ticpp::Element* elem_obj, PObjectInfo obj_info, PPropertyCategory category, std::set< PropertyType >* types )
{
	ticpp::Element* elem_category = elem_obj->FirstChildElement( CATEGORY_TAG, false );
	while ( elem_category )
	{
		// Category name attribute
		std::string cname;
		elem_category->GetAttribute( NAME_TAG, &cname );
		PPropertyCategory new_cat( new PropertyCategory( _WXSTR( cname ) ) );

		// Add category
		category->AddCategory( new_cat );

		// Recurse
		ParseProperties( elem_category, obj_info, new_cat, types );

		elem_category = elem_category->NextSiblingElement( CATEGORY_TAG, false );
	}

	ticpp::Element* elem_prop = elem_obj->FirstChildElement( PROPERTY_TAG, false );
	while ( elem_prop )
	{
		// Property Name Attribute
		std::string pname;
		elem_prop->GetAttribute( NAME_TAG, &pname );
		category->AddProperty( _WXSTR(pname) );

		std::string description;
		elem_prop->GetAttributeOrDefault( DESCRIPTION_TAG, &description, "" );

		std::string customEditor;
		elem_prop->GetAttributeOrDefault( CUSTOM_EDITOR_TAG, &customEditor, "" );

		std::string prop_type;
		elem_prop->GetAttribute( "type", &prop_type );
		PropertyType ptype;
		try
		{
			ptype = ParsePropertyType( _WXSTR( prop_type ) );
		}
		catch( wxFBException& ex )
		{
            ////wxLogError( ("Error: %s\nWhile parsing property \"%s\" of class \"%s\""), ex.what(), _WXSTR(pname).c_str(), obj_info->GetClassName().c_str() );
			elem_prop = elem_prop->NextSiblingElement( PROPERTY_TAG, false );
			continue;
		}

		// Get min value
		std::string min_value("0");
		elem_prop->GetAttribute("minvalue", &min_value,false);

		// Get max value
		std::string max_value("0");
		elem_prop->GetAttribute("maxvalue", &max_value, false);
        
		// Get read only value
		bool isReadOnly = false;
		std::string readonly_value("false");
		elem_prop->GetAttribute("readonly", &readonly_value, false);
		if(readonly_value == "true")
		{
           isReadOnly = true;
		}
		// Get default value
		std::string def_value;
		try
		{
			ticpp::Node* lastChild = elem_prop->LastChild(false);
			if (lastChild && lastChild->Type() == TiXmlNode::TEXT)
			{
				ticpp::Text* text = lastChild->ToText();
                assert(text != nullptr);
				def_value = text->Value();
			}
		}
		catch (ticpp::Exception& ex)
		{
            ////wxLogDebug(ex.what());
		}

		

		// if the property is a "bitlist" then parse all of the options
		POptionList opt_list;
		std::list< PropertyChild > children;
		if ( ptype == PT_BITLIST || ptype == PT_OPTION || ptype == PT_EDIT_OPTION )
		{
			opt_list = POptionList( new OptionList() );
			ticpp::Element* elem_opt = elem_prop->FirstChildElement( "option", false );
			while( elem_opt )
			{
				std::string macro_name;
				elem_opt->GetAttribute( NAME_TAG, &macro_name );

				std::string macro_description;
				elem_opt->GetAttributeOrDefault( DESCRIPTION_TAG, &macro_description, "" );

				opt_list->AddOption( _WXSTR(macro_name), _WXSTR(macro_description) );

				m_macroSet.insert( _WXSTR(macro_name) );

				elem_opt = elem_opt->NextSiblingElement( "option", false );
			}
		}
		else if ( ptype == PT_PARENT )
		{
			// If the property is a parent, then get the children
			def_value.clear();
			ticpp::Element* elem_child = elem_prop->FirstChildElement( "child", false );
			while ( elem_child )
			{
				PropertyChild child;

				std::string child_name;
				elem_child->GetAttribute( NAME_TAG, &child_name );
				child.m_name = _WXSTR( child_name );

				std::string child_description;
				elem_child->GetAttributeOrDefault( DESCRIPTION_TAG, &child_description, "" );
				child.m_description = _WXSTR( child_description );

				std::string child_type;
				elem_child->GetAttributeOrDefault( "type", &child_type, "QString" );
				child.m_type = ParsePropertyType( _WXSTR( child_type ) );

				// Get default value
				// Empty tags don't contain any child so this will throw in that case
				std::string child_value;
				try
				{
					ticpp::Node* lastChild = elem_child->LastChild(false);
					if (lastChild && lastChild->Type() == TiXmlNode::TEXT)
					{
						ticpp::Text* text = lastChild->ToText();
                        assert(text != nullptr);
						child_value = text->Value();
					}
				}
				catch (ticpp::Exception& ex)
				{
                    ////wxLogDebug(ex.what());
				}
				child.m_defaultValue = _WXSTR(child_value);

				// build parent default value
				if (children.size() > 0)
				{
					def_value += "; ";
				}
				def_value += child_value;

				children.push_back(child);

				elem_child = elem_child->NextSiblingElement( "child", false );
			}
		}

		// create an instance of PropertyInfo
        PPropertyInfo prop_info(new PropertyInfo(_WXSTR(pname), ptype, _WXSTR(def_value), QString::fromStdString(min_value),
                                                 QString::fromStdString(max_value), _WXSTR(description),
		                                         _WXSTR(customEditor),
		                                         opt_list, children, isReadOnly));

		// add the PropertyInfo to the property
		obj_info->AddPropertyInfo( prop_info );

		// merge property code templates, once per property type
		if ( types->insert( ptype ).second )
		{
			LangTemplateMap& propLangTemplates = m_propertyTypeTemplates[ ptype ];
			LangTemplateMap::iterator lang;
			for ( lang = propLangTemplates.begin(); lang != propLangTemplates.end(); ++lang )
			{
				if ( lang->second )
				{
					obj_info->AddCodeInfo( lang->first, lang->second );
				}
			}
		}

		elem_prop = elem_prop->NextSiblingElement( PROPERTY_TAG, false );
	}
}


void ObjectDatabase::ParseProperties(ticpp::Element* elem_obj, PLcdTemplateInfo obj_info, std::set<PropertyType>* types)
{
	ticpp::Element* elem_prop = elem_obj->FirstChildElement( PROPERTY_TAG, false );
	while ( elem_prop )
	{
		// Property Name Attribute
		std::string pname;
		elem_prop->GetAttribute( NAME_TAG, &pname );
	
		std::string description;
		elem_prop->GetAttributeOrDefault( DESCRIPTION_TAG, &description, "" );

		std::string customEditor;
		elem_prop->GetAttributeOrDefault( CUSTOM_EDITOR_TAG, &customEditor, "" );

		std::string prop_type;
		elem_prop->GetAttribute( "type", &prop_type );
		PropertyType ptype;
		try
		{
			ptype = ParsePropertyType( _WXSTR( prop_type ) );
		}
		catch( wxFBException& ex )
		{
            ////wxLogError( ("Error: %s\nWhile parsing property \"%s\" of class \"%s\""), ex.what(), _WXSTR(pname).c_str(), obj_info->GetClassName().c_str() );
			elem_prop = elem_prop->NextSiblingElement( PROPERTY_TAG, false );
			continue;
		}

		// Get min value
		std::string min_value("0");
		elem_prop->GetAttribute("minvalue", &min_value,false);

		// Get max value
		std::string max_value("0");
		elem_prop->GetAttribute("maxvalue", &max_value, false);
        
		// Get read only value
		bool isReadOnly = false;
		std::string readonly_value("false");
		elem_prop->GetAttribute("readonly", &readonly_value, false);
		if(readonly_value == "true")
		{
           isReadOnly = true;
		}
		// Get default value
		std::string def_value;
		try
		{
			ticpp::Node* lastChild = elem_prop->LastChild(false);
			if (lastChild && lastChild->Type() == TiXmlNode::TEXT)
			{
				ticpp::Text* text = lastChild->ToText();
                //wxASSERT(text);
				def_value = text->Value();
			}
		}
		catch (ticpp::Exception& ex)
		{
            //wxLogDebug(ex.what());
		}

		// if the property is a "bitlist" then parse all of the options
		POptionList opt_list;
		std::list< PropertyChild > children;
		if ( ptype == PT_BITLIST || ptype == PT_OPTION || ptype == PT_EDIT_OPTION )
		{
			opt_list = POptionList( new OptionList() );
			ticpp::Element* elem_opt = elem_prop->FirstChildElement( "option", false );
			while( elem_opt )
			{
				std::string macro_name;
				elem_opt->GetAttribute( NAME_TAG, &macro_name );

				std::string macro_description;
				elem_opt->GetAttributeOrDefault( DESCRIPTION_TAG, &macro_description, "" );

				opt_list->AddOption( _WXSTR(macro_name), _WXSTR(macro_description) );

				m_macroSet.insert( _WXSTR(macro_name) );

				elem_opt = elem_opt->NextSiblingElement( "option", false );
			}
		}
		else if ( ptype == PT_PARENT )
		{
			// If the property is a parent, then get the children
			def_value.clear();
			ticpp::Element* elem_child = elem_prop->FirstChildElement( "child", false );
			while ( elem_child )
			{
				PropertyChild child;

				std::string child_name;
				elem_child->GetAttribute( NAME_TAG, &child_name );
				child.m_name = _WXSTR( child_name );

				std::string child_description;
				elem_child->GetAttributeOrDefault( DESCRIPTION_TAG, &child_description, "" );
				child.m_description = _WXSTR( child_description );

				std::string child_type;
				elem_child->GetAttributeOrDefault( "type", &child_type, "QString" );
				child.m_type = ParsePropertyType( _WXSTR( child_type ) );

				// Get default value
				// Empty tags don't contain any child so this will throw in that case
				std::string child_value;
				try
				{
					ticpp::Node* lastChild = elem_child->LastChild(false);
					if (lastChild && lastChild->Type() == TiXmlNode::TEXT)
					{
						ticpp::Text* text = lastChild->ToText();
                        //wxASSERT(text);
						child_value = text->Value();
					}
				}
				catch (ticpp::Exception& ex)
				{
                    //wxLogDebug(ex.what());
				}
				child.m_defaultValue = _WXSTR(child_value);

				// build parent default value
				if (children.size() > 0)
				{
					def_value += "; ";
				}
				def_value += child_value;

				children.push_back(child);

				elem_child = elem_child->NextSiblingElement( "child", false );
			}
		}

		// create an instance of PropertyInfo
        PPropertyInfo prop_info(new PropertyInfo(_WXSTR(pname), ptype, _WXSTR(def_value), QString::fromStdString(min_value),
                                                 QString::fromStdString(max_value), _WXSTR(description),
		                                         _WXSTR(customEditor),
		                                         opt_list, children, isReadOnly));

		// add the PropertyInfo to the property
		obj_info->AddPropertyInfo( prop_info );
		
		elem_prop = elem_prop->NextSiblingElement( PROPERTY_TAG, false );
	}
}

void ObjectDatabase::ParseEvents( ticpp::Element* elem_obj, PObjectInfo obj_info, PPropertyCategory category )
{
	ticpp::Element* elem_category = elem_obj->FirstChildElement( CATEGORY_TAG, false );
	while ( elem_category )
	{
		// Category name attribute
		std::string cname;
		elem_category->GetAttribute( NAME_TAG, &cname );
		PPropertyCategory new_cat( new PropertyCategory( _WXSTR( cname ) ) );

		// Add category
		category->AddCategory( new_cat );

		// Recurse
		ParseEvents( elem_category, obj_info, new_cat );

		elem_category = elem_category->NextSiblingElement( CATEGORY_TAG, false );
	}

	ticpp::Element* elem_evt = elem_obj->FirstChildElement( EVENT_TAG, false );
	while ( elem_evt )
	{
		// Event Name Attribute
		std::string evt_name;
		elem_evt->GetAttribute( NAME_TAG, &evt_name );
		category->AddEvent( _WXSTR(evt_name) );

		// Event class
		std::string evt_class;
		elem_evt->GetAttributeOrDefault( EVENT_CLASS_TAG, &evt_class, "wxEvent" );


		// Help string
		std::string description;
		elem_evt->GetAttributeOrDefault( DESCRIPTION_TAG, &description, "" );

		// Get default value
		std::string def_value;
		try
		{
			ticpp::Node* lastChild = elem_evt->LastChild(false);
			if (lastChild && lastChild->Type() == TiXmlNode::TEXT)
			{
				ticpp::Text* text = lastChild->ToText();
                //wxASSERT(text);
				def_value = text->Value();
			}
		}
		catch (ticpp::Exception& ex)
		{
            //wxLogDebug(ex.what());
		}

		// create an instance of EventInfo
		PEventInfo evt_info(
		  new EventInfo( _WXSTR(evt_name),  _WXSTR(evt_class), _WXSTR(def_value), _WXSTR(description)));

		// add the EventInfo to the event
		obj_info->AddEventInfo(evt_info);

		elem_evt = elem_evt->NextSiblingElement( EVENT_TAG, false );
	}
}


void ObjectDatabase::LoadLcdTemplates(const QString& file)
{
	try
	{
		ticpp::Document doc;
		XMLUtils::LoadXMLFile( doc, true, file );
        ticpp::Element* root = doc.FirstChildElement( PACKAGE_TAG );
		ticpp::Element* elem_obj = root->FirstChildElement( OBJINFO_TAG, false );

		while (elem_obj)
		{
			std::string class_name;
			std::string name;
			elem_obj->GetAttribute( CLASS_TAG, &class_name );
			elem_obj->GetAttribute( NAME_TAG, &name );

			std::string type;
			elem_obj->GetAttribute( "type", &type );

			std::string wxver;
			elem_obj->GetAttributeOrDefault( WXVERSION_TAG, &wxver, "" );
			if( wxver != "" )
			{
				long wxversion = 0;
				// skip widgets supported by higher wxWidgets version than used for the build
//				if( (! _WXSTR(wxver).ToLong( &wxversion ) ) || (wxversion > wxVERSION_NUMBER) )
//				{
//					elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
//					continue;
//				}
			}

			PLcdTemplateInfo obj_info( new LcdTemplateInfo( _WXSTR(class_name),  _WXSTR(name),GetObjectType( _WXSTR(type) )) );


			// Parse the Properties
			std::set< PropertyType > types;
			ParseProperties( elem_obj, obj_info, &types );

			// Add the LcdTemplateInfo to the vector
			m_lcdTemplates.push_back( obj_info );


			elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
		}
	}
	catch ( ticpp::Exception& ex )
	{
        //THROW_WXFBEX( _WXSTR(ex.m_details) );
	}

	return;
}

bool ObjectDatabase::ShowInPalette(QString type)
{
    return (type == ("form")					||
            type == ("wizard")               ||
            type == ("wizardpagesimple")     ||
            type == ("menubar_form")			||
            type == ("toolbar_form")			||
            type == ("sizer")				||
            type == ("gbsizer")				||
            type == ("menu")					||
            type == ("menuitem")				||
            type == ("submenu")				||
            type == ("tool")					||
            type == ("ribbonbar")			||
            type == ("ribbonpage")			||
            type == ("ribbonpanel")      		||
            type == ("ribbonbuttonbar")  		||
            type == ("ribbonbutton")  			||
            type == ("ribbondropdownbutton" )	||
            type == ("ribbonhybridbutton" )  	||
            type == ("ribbontogglebutton" )  	||
            type == ("ribbontoolbar")	   		||
            type == ("ribbontool")		   	||
            type == ("ribbondropdowntool" )  	||
            type == ("ribbonhybridtool" ) 		||
            type == ("ribbontoggletool" )  		||
            type == ("ribbongallery")  			||
            type == ("ribbongalleryitem")		||
            type == ("dataviewctrl")			||
            type == ("dataviewtreectrl")		||
            type == ("dataviewlistctrl")		||
            type == ("dataviewlistcolumn")		||
            type == ("dataviewcolumn")		||
            type == ("notebook")				||
            type == ("flatnotebook")			||
            type == ("listbook")				||
            type == ("simplebook")			||
            type == ("choicebook")			||
            type == ("auinotebook")			||
            type == ("widget")				||
            type == ("expanded_widget")		||
            type == ("propgrid")		||
            type == ("propgridman")		||
            type == ("propgridpage")		||
            type == ("propgriditem")		||
            type == ("statusbar")			||
            type == ("component")			||
            type == ("container")			||
            type == ("menubar")				||
            type == ("treelistctrl")			||
            type == ("treelistctrlcolumn")	||
            type == ("toolbar")				||
            type == ("nonvisual")			||
            type == ("splitter")
			);
}



PropertyType ObjectDatabase::ParsePropertyType( QString str )
{
	PropertyType result;
	PTMap::iterator it = m_propTypes.find(str);
	if (it != m_propTypes.end())
		result = it->second;
	else
	{
        THROW_WXFBEX( QString::Format( ("Unknown property type \"%s\""), str.c_str() ) );
	}

	return result;
}

QString  ObjectDatabase::ParseObjectType( QString str )
{
	return str;
}


#define PT(x,y) m_propTypes.insert(PTMap::value_type(x,y))
void ObjectDatabase::InitPropertyTypes()
{
    PT( ("bool"),			PT_BOOL		);
    PT( ("text"),			PT_TEXT		);
    PT( ("int"),				PT_INT		);
    PT( ("uint"),			PT_UINT		);
    PT( ("bitlist"),		PT_BITLIST		);
    PT( ("intlist"),		PT_INTLIST		);
    PT( ("uintlist"),	PT_UINTLIST		);
    PT(("intpairlist"), PT_INTPAIRLIST);
    PT(("uintpairlist"), PT_UINTPAIRLIST);
    PT( ("option"),		PT_OPTION		);
    PT( ("macro"),		PT_MACRO		);
    PT( ("path"),		PT_PATH			);
    PT( ("file"),		PT_FILE			);
    PT( ("QString"), 	PT_QString		);
    PT( ("wxPoint"),		PT_WXPOINT		);
    PT( ("wxSize"),		PT_WXSIZE		);
    PT( ("wxFont"),		PT_WXFONT		);
    PT( ("wxColour"),	PT_WXCOLOUR		);
    PT( ("bitmap"),		PT_BITMAP		);
    PT( ("QString_i18n"),PT_QString_I18N);
    PT( ("stringlist"),	PT_STRINGLIST	);
    PT( ("float"),		PT_FLOAT		);
    PT( ("parent"),		PT_PARENT		);
    PT( ("editoption"),	PT_EDIT_OPTION	);
    PT( ("FlashImageSelect"),	PT_FLASH_IMAGE_SELECT	);
    PT( ("DlgBackgroud"),	PT_DIALOG_BACKGROUD	);
    PT( ("ButtonBackgroud"),	PT_BUTTON_BACKGROUD );
    PT( ("FlashFont"),	PT_FLASH_FONT );
    PT( ("SliderCursor"),	PT_SLIDER_CURSOR );
}

bool ObjectDatabase::LoadObjectTypes()
{
	ticpp::Document doc;
    QString xmlPath = m_xmlPath + ("objtypes.xml");
	XMLUtils::LoadXMLFile( doc, true, xmlPath );

	// First load the object types, then the children
	try
	{
		ticpp::Element* root = doc.FirstChildElement("definitions");
		ticpp::Element* elem = root->FirstChildElement( "objtype" );
		while ( elem )
		{
			bool hidden;
			elem->GetAttributeOrDefault( "hidden", &hidden, false );

			bool item;
			elem->GetAttributeOrDefault( "item", &item, false );

			QString name = _WXSTR( elem->GetAttribute("name") );

			PObjectType objType( new ObjectType( name, (int)m_types.size(), hidden, item ) );
			m_types.insert( ObjectTypeMap::value_type( name, objType ) );

			elem = elem->NextSiblingElement( "objtype", false );
		}

		// now load the children
		elem = root->FirstChildElement("objtype");
		while (elem)
		{
			QString name = _WXSTR( elem->GetAttribute("name") );

			// get the objType
			PObjectType objType = GetObjectType( name );
			ticpp::Element* child = elem->FirstChildElement( "childtype", false );
			while ( child )
			{
				int nmax = -1; // no limit
				int aui_nmax = -1; // no limit
				child->GetAttributeOrDefault( "nmax", &nmax, -1 );
				child->GetAttributeOrDefault( "aui_nmax", &aui_nmax, -1 );

				QString childname = _WXSTR( child->GetAttribute("name") );

				PObjectType childType = GetObjectType( childname );
				if ( !childType )
				{
                    //wxLogError( ("No Object Type found for \"%s\""), childname.c_str() );
					continue;
				}

				objType->AddChildType( childType, nmax, aui_nmax );

				child = child->NextSiblingElement( "childtype", false );
			}
			elem = elem->NextSiblingElement( "objtype", false );
		}
	}
	catch( ticpp::Exception& ex )
	{
        //wxLogError( _WXSTR( ex.m_details ) );
		return false;
	}

	return true;
}

PObjectType ObjectDatabase::GetObjectType(QString name)
{
	PObjectType type;
	ObjectTypeMap::iterator it = m_types.find(name);
	if (it != m_types.end())
		type = it->second;

	return type;
}
